﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;

namespace Main.Common
{
    public static class ReflectionExtension
    {
        public static IEnumerable<T> FindAll<T>(this AppDomain domain)
        {
            List<T> ret = new List<T>();
            domain.FindAll<T>((TType, TVal) => ret.Add(TVal));
            return ret;        
        }

        public static void FindAll<T>(this AppDomain domain, Action<Type,T> found)
        {
            List<T> ret = new List<T>();
            Type TypeOfService = typeof(T);
            foreach (Assembly assembly in domain.GetAssemblies())
            {
                foreach (Type t in assembly.GetTypes().Where(o => TypeOfService.IsAssignableFrom(o)))
                {
                    T o = t.CreateAs<T>();
                    if (o != null)
                        found(t, o);
                }
            }        
        }

        public static IEnumerable<Type> FindTypes<T>(this AppDomain domain)
        {
            List<Type> ret = new List<Type>();
            domain.FindTypes<T>((TType) => ret.Add(TType));
            return ret;
        }

        public static void FindTypes<T>(this AppDomain domain, Action<Type> found)
        {
            Type TypeOfService = typeof(T);
            foreach (Assembly assembly in domain.GetAssemblies())
            {
                foreach (Type t in assembly.GetTypes().Where(o => TypeOfService.IsAssignableFrom(o)))
                {
                    found(t);
                }
            }
        }

        public static object Create(this Type type)
        {
            if (type.IsClass && !type.IsAbstract)
            {
                ConstructorInfo cinfo = type.GetConstructor(Type.EmptyTypes);
                if (cinfo != null && cinfo.IsPublic)
                {
                    return cinfo.Invoke(null);
                }
            }
            return null;
        }

        public static T CreateAs<T>(this Type type)
        {
            return (T)type.Create();
        }
    }
}
